#include "EmbryoIndividual.h"

#include <cstdlib>
#include <new>
using std::bad_alloc;

#include "../../../base.h"
#include "../../../qt/Logger.h"

#include "EmbryoEvaluator.h"
#include "RbnEmbryoGenome.h"

#include "../rbn/RbnGenome.h"
using GA::RbnGenome;

//TODO centralise ?
#define GENE_MUTATION_PROBABILITY 0.02

namespace GA {

/*
	EmbryoIndividual
*/

/*	public	*/

EmbryoIndividual* EmbryoIndividual::newRandom(EmbryoEvaluator& evaluator) {
	/* genome */
	EmbryoGenome* genome = RbnEmbryoGenome::newRandom();

	/* individual */
	EmbryoIndividual* individual = new EmbryoIndividual(genome, evaluator);

	return individual;
}

EmbryoIndividual::EmbryoIndividual(EmbryoGenome* genome, EmbryoEvaluator& evaluator) :
	_genome(genome),
	_evaluator(evaluator),
	_fitness(0.0),
	_evaluated(false) {}

EmbryoIndividual::EmbryoIndividual(EmbryoIndividual const& individual) :
	GA::Individual(),
	_evaluator(individual._evaluator),
	_fitness(individual._fitness),
	_evaluated(individual._evaluated) {

	/* genome */
	_genome = static_cast<EmbryoGenome*>(individual.getGenome().copy());
}

void* EmbryoIndividual::operator new(size_t size) {
//	Logger::debug("=== EmbryoIndividual::operator new()");

	/* memory */
	void* memory = malloc(size); 

	/* check validity */
	if (memory == 0) {
		throw bad_alloc();
	}

	return memory;
}

void EmbryoIndividual::operator delete(void* memory) {
//	Logger::debug("=== EmbryoIndividual::operator delete()");
	free(memory);
}

EmbryoIndividual::~EmbryoIndividual() {
	delete _genome;
}

const EmbryoGenome& EmbryoIndividual::getGenome() const {
	return *_genome;
}

Individual* EmbryoIndividual::copy() const {
	/* copy */
	return new EmbryoIndividual(*this);
}

Individual* EmbryoIndividual::mate(Individual const& individual) const {
//	Logger::debug("=== EmbryoIndividual::mate()");

	/* cast param */
	const EmbryoIndividual& embryoIndividual = static_cast<EmbryoIndividual const&>(individual);

	/* offspring genome */
	EmbryoGenome* offspringGenome = static_cast<EmbryoGenome*>(_genome->crossover(embryoIndividual.getGenome()));
	offspringGenome->mutate(GENE_MUTATION_PROBABILITY);

	/* offspring */
	EmbryoIndividual* offspring = new EmbryoIndividual(offspringGenome, _evaluator);

	return (Individual*)offspring;
}

void EmbryoIndividual::evaluate() {
	/* evaluate */
	_fitness = _evaluator.evaluate(*this);
	_evaluated = true;
}

bool EmbryoIndividual::operator>(Individual const& individual) const {
	const EmbryoIndividual& embryoIndividual = static_cast< EmbryoIndividual const&>(individual);

	/* compare fitnesses */
	return this->getFitness() > embryoIndividual.getFitness();
}

double EmbryoIndividual::getFitness() const {
//	Logger::debug("=== EmbryoIndividual::getFitness()");
	assert(_evaluated);
	return _fitness;
}

//std::string EmbryoIndividual::toString() const {
//	//FIX
//	return "";
//}

} // GA

